package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackMediaInfoVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private VodConstantProperties vodConstantProperties;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;


    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long trackId, Integer trackCount) {
        //  声明集合列表
        List<TrackInfo> trackInfoList = new ArrayList<>();
        //  select * from track_info where id > 18031 and album_id = 341 limit 10;
        //  通过声音Id 获取到声音对象
        TrackInfo trackInfo = this.trackInfoMapper.selectById(trackId);
        //  trackCount可以为0；表示购买的是本集！

        if (trackCount > 0) {
            Result<List<Long>> userPaidTrackListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
            List<Long> userPaidTrackIdList = userPaidTrackListResult.getData();
            //  构建查询条件
            LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId());
            wrapper.gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
            //  使用Id 作为条件
            //  wrapper.gt(TrackInfo::getId, trackId);
            if (!CollectionUtils.isEmpty(userPaidTrackIdList)){
                //  id not in (18034,18035) 除去已购买的！
                wrapper.notIn(TrackInfo::getId,userPaidTrackIdList);
            }
            wrapper.last(" limit " + trackCount);
            //  给集合赋值
            trackInfoList = trackInfoMapper.selectList(wrapper);
            //  select * from track_info where id > 18031 and album_id = 341 and id not in (18034,18035) limit 10; 排除用户已购买的声音Id;
            //  trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getId, trackId).last(" limit " + trackCount));
        } else {
            //  trackCount<0的时候直接抛出异常了！ 等于0的时候
            trackInfoList.add(trackInfo);
        }
        //  保证查询到的数据必须是同一张专辑！
        return trackInfoList;
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId) {
        //  1.  先通过声音Id获取到声音对象
        TrackInfo trackInfo = this.trackInfoMapper.selectById(trackId);
        //  根据专辑Id获取到专辑对象
        AlbumInfo albumInfo = this.albumInfoMapper.selectById(trackInfo.getAlbumId());
        //  用户购买过当前专辑的声音Id列表； 用户Id 可以通过在用户微服务中获取！
        Result<List<Long>> trackIdListResult = userInfoFeignClient.findUserPaidTrackList(trackInfo.getAlbumId());
        Assert.notNull(trackIdListResult, "用户信息获取失败！");
        List<Long> trackIdList = trackIdListResult.getData();
        //  用户可能没有购买过当前专辑对应的声音列表！这个集合可以为空！
        //  获取从当前这个声音Id 开始，应该有多少集声音！
        //  select * from track_info where track_info.order_num > 6 and album_id = 341;
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TrackInfo::getAlbumId, trackInfo.getAlbumId()).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(wrapper);
        //  排查用户已购买的声音集合列表
        List<TrackInfo> noPaidTrackList = trackInfoList.stream().filter(trackInfo1 -> !trackIdList.contains(trackInfo1.getId())).collect(Collectors.toList());

        //  声明一个listMap 集合
        List<Map<String, Object>> list = new ArrayList<>();
        //  这个集合大于0
        if (noPaidTrackList.size() >= 0) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "本集"); // 显示文本
            map.put("price", albumInfo.getPrice()); // 专辑声音对应的价格
            map.put("trackCount", 0); // 记录购买集数 0 表示购买本集
            list.add(map);
        }
        if (noPaidTrackList.size() > 0 && noPaidTrackList.size() <= 10) {
            Map<String, Object> map = new HashMap<>();
            int count = noPaidTrackList.size();
            map.put("name", "后" + count + "集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(count)))); // 专辑声音对应的价格
            map.put("trackCount", count); // 记录购买集数
            list.add(map);
        }
        //  判断
        if (noPaidTrackList.size() > 10) {
            Map<String, Object> map = new HashMap<>();
            map.put("name", "本10集"); // 显示文本
            map.put("price", albumInfo.getPrice().multiply(new BigDecimal("10"))); // 专辑声音对应的价格
            map.put("trackCount", 10); // 记录购买集数
            list.add(map);
        }

        // 后20集
        if (noPaidTrackList.size() > 10 && noPaidTrackList.size() <= 20) {
            Map<String, Object> map = new HashMap<>();
            int count = noPaidTrackList.size();
            BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
            map.put("name", "后" + count + "集");
            map.put("price", price);
            map.put("trackCount", count);
            list.add(map);
        }
        if (noPaidTrackList.size() > 20) {
            Map<String, Object> map = new HashMap<>();
            BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal("20"));
            map.put("name", "后20集");
            map.put("price", price);
            map.put("trackCount", 20);
            list.add(map);
        }

        //后30集
        if (noPaidTrackList.size() > 20 && noPaidTrackList.size() <= 30) {
            Map<String, Object> map = new HashMap<>();
            int count = noPaidTrackList.size();
            BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
            map.put("name", "后" + count + "集");
            map.put("price", price);
            map.put("trackCount", count);
            list.add(map);
        }
        if (noPaidTrackList.size() > 30) {
            Map<String, Object> map = new HashMap<>();
            BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal("30"));
            map.put("name", "后30集");
            map.put("price", price);
            map.put("trackCount", 30);
            list.add(map);
        }

        //后50集
        if (noPaidTrackList.size() > 30 && noPaidTrackList.size() <= 50) {
            Map<String, Object> map = new HashMap<>();
            int count = noPaidTrackList.size();
            BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal(count));
            map.put("name", "后" + count + "集");
            map.put("price", price);
            map.put("trackCount", count);
            list.add(map);
        }
        // 最多购买50集;
        if (noPaidTrackList.size() > 50) {
            Map<String, Object> map = new HashMap<>();
            BigDecimal price = albumInfo.getPrice().multiply(new BigDecimal("50"));
            map.put("name", "后50集");
            map.put("price", price);
            map.put("trackCount", 50);
            list.add(map);
        }
        //  返回list 集合
        return list;
    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> albumTrackListVoPage, Long albumId, Long userId) {
        //  1.  先获取到所有的声音列表！
        IPage<AlbumTrackListVo> albumTrackListVoIPage = trackInfoMapper.selectAlbumTrackPage(albumTrackListVoPage, albumId);
        //  获取到专辑对象
        AlbumInfo albumInfo = this.albumInfoMapper.selectById(albumId);
        //  2.  判断当前这个用户是否登录！
        if (null == userId) {
            //  判断专辑的类型！ 付费类型: 0102-vip免费、0103-付费
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())) {
                //  需要设置除免费试听的声音之外，所有声音都需要付费！
                Integer tracksForFreeCount = albumInfo.getTracksForFree();
                for (AlbumTrackListVo trackListVo : albumTrackListVoIPage.getRecords()) {
                    if (trackListVo.getOrderNum() > tracksForFreeCount) {
                        //  设置付费标识
                        trackListVo.setIsShowPaidMark(true);
                    }
                }
                //  6以后
                //  albumTrackListVoIPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFreeCount).forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
            }
            return albumTrackListVoIPage;
        } else {
            //  定义一个变量
            boolean isNeedPaid = false;
            //  当前用户已经登录! 判断当前专辑的类型 0102-vip免费
            if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(albumInfo.getPayType())) {
                //  看用户是否是vip
                Result<UserInfoVo> infoVoResult = this.userInfoFeignClient.getUserInfoVo(userId);
                Assert.notNull(infoVoResult, "用户信息获取失败！");
                UserInfoVo userInfoVo = infoVoResult.getData();
                //  判断当前这个用户的身份
                if ((userInfoVo.getIsVip() == 1 && userInfoVo.getVipExpireTime().before(new Date())) || userInfoVo.getIsVip() == 0) {
                    //  需要付费
                    isNeedPaid = true;
                }
            } else if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(albumInfo.getPayType())) {
                //  需要付费
                isNeedPaid = true;
            }
            //  统一处理付费情况.
            if (isNeedPaid) {
                //  3.  判断用户是否购买过专辑或声音！ 需要将对应的声音设置为免费！
                //  当前专辑对应的声音列表中；是否有用户已购买的记录! 如果有购买记录，则设置当前声音为免费！
                //  获取当前专辑对应的付费声音列表!
                List<AlbumTrackListVo> albumTrackListPaidList = albumTrackListVoIPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree()).collect(Collectors.toList());
                List<Long> trackIdList = albumTrackListPaidList.stream().map(AlbumTrackListVo::getTrackId).collect(Collectors.toList());
                //  远程调用！用户微服务 map key = trackId value=0 或 1 0表示未购买过，1表示购买过！
                Result<Map<Long, Integer>> mapResult = userInfoFeignClient.userIsPaidTrack(albumId, trackIdList);
                Assert.notNull(mapResult, "远程调用用户微服务失败！");
                Map<Long, Integer> map = mapResult.getData();

                //  设置是覅需要付费标识;
                for (AlbumTrackListVo albumTrackListVo : albumTrackListPaidList) {
                    //  三元表达式:
//                    Boolean isPaid = ;
                    albumTrackListVo.setIsShowPaidMark(map.get(albumTrackListVo.getTrackId()) == 0);
//                    if (map.get(albumTrackListVo.getTrackId()) == 1){
//                        //  设置免费
//                        albumTrackListVo.setIsShowPaidMark(false);
//                    } else {
//                        //  设置付费
//                        albumTrackListVo.setIsShowPaidMark(true);
//                    }
                }
            }
            //  返回数据
            return albumTrackListVoIPage;
        }

    }

    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        //  修改的数据被封装到 trackInfoVo 中！
        try {
            //  创建声音对象
            TrackInfo trackInfo = this.getById(trackId);
            //  先获取到原有的声音Id
            String mediaFileId = trackInfo.getMediaFileId();
            //  属性拷贝
            BeanUtils.copyProperties(trackInfoVo, trackInfo);
            //  判断原有的声音Id 与 现在修改的声音Id 是否一致！
            if (!mediaFileId.equals(trackInfoVo.getMediaFileId())) {
                //  说明声音已被修改！
                //  删除云点播的声音. 点播删除成功.
                vodService.removeMediaById(mediaFileId);
                //  赋值新的声音数据
                TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
                trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
                trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
                trackInfo.setMediaSize(trackMediaInfoVo.getSize());
                trackInfo.setMediaType(trackMediaInfoVo.getType());
            }
            //  声音统计状态，暂时不需要修改！
            //  修改track_info数据
            this.trackInfoMapper.updateById(trackInfo);
        } catch (BeansException e) {
            log.error("修改失败{}", e.getMessage());
            throw new GuiguException(201, "修改失败！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long trackId) {
        //  先根据声音Id获取到专辑对象
        TrackInfo trackInfo = this.trackInfoMapper.selectById(trackId);
        //  保存的时候： track_info track_stat 更新：album_info,  更新：album_info, 删除：track_info, track_stat，vod
        //  track_info
        trackInfoMapper.deleteById(trackId);
        //  track_stat
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        //  先根据专辑Id 查询专辑对象
        AlbumInfo albumInfo = this.albumInfoMapper.selectById(trackInfo.getAlbumId());
        //  包含声音总数-1
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        //  album_info
        this.albumInfoMapper.updateById(albumInfo);
        //  维护声音表的order_num;
        //  update track_info set order_num = order_num - 1 where and order_num > 51 and album_id = 1 and is_deleted = 0
        this.trackInfoMapper.updateOrderNum(trackInfo.getOrderNum(), trackInfo.getAlbumId());
        //  删除云点播;
        vodService.removeMediaById(trackInfo.getMediaFileId());

    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(Page<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
        //  调用mapper层方法
        return trackInfoMapper.selectUserTrackPage(trackListVoPage, trackInfoQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo, Long userId) {
        //	track_info track_stat album_info
        //	创建声音对象
        TrackInfo trackInfo = new TrackInfo();
        //	属性拷贝
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        //	赋值用户Id
        trackInfo.setUserId(userId);
        //	赋值 order_num; 1.查询当前声音列表中的order_num 最大值，然后+1; 2.直接查询专辑中包含声音的总数+1;
        //	查询专辑对象
        AlbumInfo albumInfo = this.albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        //  需要通过上传的文件Id 去 云点播中获取数据!
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        //  赋值声音相关数据
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaDuration(trackMediaInfoVo.getDuration());
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfoMapper.insert(trackInfo);
        //  track_stat
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        this.saveTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);

        //  更新专辑中包含声音的总数;
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        this.albumInfoMapper.updateById(albumInfo);

    }

    private void saveTrackStat(Long trackId, String statPlay) {

        //  创建对象
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statPlay);
        trackStat.setStatNum(0);
        //  保存统计信息
        trackStatMapper.insert(trackStat);

    }

    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {
        //	初始化一个上传客户端对象
        VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());
        //	构建一个上传路径
        String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
        //	构造上传请求对象
        VodUploadRequest request = new VodUploadRequest();
        request.setMediaFilePath(tempPath);
        //	调用上传方法
        try {
            VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);
            log.info("Upload FileId = {}", response.getFileId());
            //	创建一个map 集合对象
            Map<String, Object> hashMap = new HashMap<>();
            hashMap.put("mediaFileId", response.getFileId());
            hashMap.put("mediaUrl", response.getMediaUrl());
            //	返回map
            return hashMap;
        } catch (Exception e) {
            // 业务方进行异常处理
            log.error("Upload Err", e);
        }
        //	默认返回
        return null;
    }
}
